package gutils

import (
	"math/rand"
	"time"

	"golang.org/x/exp/constraints"
)

// RemoveRepeat 从切片中删除重复的元素，保持元素的原始顺序。
//
// 参数:
//   - list: 包含可能重复元素的输入切片
//
// 返回值:
//   - []T: 返回一个新的切片，包含所有不重复的元素，保持原始顺序
//
// 示例:
//
//	nums := []int{1, 2, 2, 3, 3, 4}
//	unique := RemoveRepeat(nums) // 返回 [1, 2, 3, 4]
func RemoveRepeat[T comparable](list []T) (res []T) {
	// 创建一个临时map用来存储数组元素
	temp := make(map[T]bool)

	for _, v := range list {
		// 遍历数组元素, 判断此元素是否已经存在map中
		if !temp[v] {
			temp[v] = true
			res = append(res, v)
		}
	}
	return
}

// FindArrayMinValue 在切片中查找最小值。
//
// 参数:
//   - arr: 包含可比较元素的输入切片
//
// 返回值:
//   - T: 切片中的最小值，如果切片为空则返回类型的零值
//   - bool: 如果切片非空返回true，为空返回false
//
// 示例:
//
//	nums := []int{3, 1, 4, 1, 5, 9}
//	min, ok := FindArrayMinValue(nums) // 返回 1, true
//	empty := []int{}
//	min, ok := FindArrayMinValue(empty) // 返回 0, false
func FindArrayMinValue[T constraints.Ordered](arr []T) (T, bool) {
	if len(arr) == 0 {
		var zero T // 返回零值和false表示切片为空
		return zero, false
	}

	minNum := arr[0]
	for _, v := range arr[1:] {
		if v < minNum {
			minNum = v
		}
	}
	return minNum, true
}

// EnsureLength 强制让切片的长度为指定长度（不足补默认值，过长截断）
func EnsureLength[T any](s []T, length int, defaultValue T) []T {
	if length < 0 {
		length = 0 // 防止负数
	}

	result := make([]T, length)
	copy(result, s) // 自动截断

	// 填充默认值（如果原切片长度不足）
	for i := len(s); i < length; i++ {
		result[i] = defaultValue
	}
	return result
}

// PadWith 函数使用泛型创建指定类型的结构体切片
// 参数：
//   - n: 需要创建的结构体实例数量
//   - zero: 结构体类型的零值，用于推断类型
//
// 返回：
//   - 包含n个结构体实例的切片
// 示例:
//  people := PadWith(5, Person{}) /
func PadWith[T any](n int, zero T) []T {
	result := make([]T, n)
	// 注意：切片中的元素已经初始化为该类型的零值
	// 如果需要进一步初始化，可以在这里添加循环处理
	return result
}

// RandomElement 从切片中随机选择一个元素。
//
// 参数:
//   - slice: 输入切片
//
// 返回值:
//   - T: 随机选择的元素，如果切片为空则返回类型的零值
//
// 示例:
//
//	names := []string{"Alice", "Bob", "Charlie", "Dave"}
//	name := RandomElement(names) // 返回随机选择的名字
//	empty := []string{}
//	name := RandomElement(empty) // 返回 ""
func RandomElement[T any](slice []T) T {
	if len(slice) == 0 {
		var zero T
		return zero
	}
	source := rand.NewSource(time.Now().UnixNano())
	rand.New(source)
	index := rand.Intn(len(slice))
	return slice[index]
}
